/***********************************************************************
	filename: 	CEGUIAnimateset.cpp
	created:	21/2/2004
	author:		Paul D Turner
	
	purpose:	Implements the Animateset class
*************************************************************************/
/***************************************************************************
 *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 ***************************************************************************/
#include "CEGUIAnimateset.h"
#include "CEGUIExceptions.h"
#include "CEGUITexture.h"
#include "CEGUIRenderer.h"
#include "CEGUISystem.h"
#include "CEGUIAnimateset_xmlHandler.h"
#include "CEGUILogger.h"
#include "CEGUIDataContainer.h"
#include "CEGUIXMLParser.h"
#include "CEGUIXMLSerializer.h" 
#include "CEGUIPropertyHelper.h" 
#include <iostream>
#include <cmath>

// Start of CEGUI namespace section
namespace CEGUI
{

/*************************************************************************
	Definition of static /const data for Animateset (and sub-classes)
*************************************************************************/
// Declared in Animateset
const char	Animateset::AnimatesetSchemaName[]			= "Animateset.xsd";
String Animateset::d_defaultResourceGroup;


/*************************************************************************
	constructor
*************************************************************************/
Animateset::Animateset(const String& name) :
	d_name(name)
{
	
}


/*************************************************************************
	construct and initialise Animateset from the specified file.
*************************************************************************/
Animateset::Animateset(const String& filename, const String& resourceGroup)
{
	// defaults for scaling options
	d_autoScale = false;
	
	load(filename, resourceGroup);
}

/*************************************************************************
	destructor
*************************************************************************/
Animateset::~Animateset(void)
{
	unload();
}

/*************************************************************************
	load Animateset data from the specified file
*************************************************************************/
void Animateset::load(const String& filename, const String& resourceGroup)
{
	// unload old data and texture.
	unload();

	if (filename.empty())
	{
		throw InvalidRequestException("Animateset::load - Filename supplied for Animateset loading must be valid");
	}

    // create handler object
    Animateset_xmlHandler handler(this);

	// do parse (which uses handler to create actual data)
	try
	{
        System::getSingleton().getXMLParser()->parseXMLFile(
                handler, filename, AnimatesetSchemaName,
                resourceGroup.empty() ? d_defaultResourceGroup : resourceGroup);
	}
	catch(...)
	{
		unload();

        Logger::getSingleton().logEvent("Animateset::load - loading of Animateset from file '" + filename +"' failed.", Errors);
        throw;
	}

}

 
/*************************************************************************
	return the Animate object for the named image
*************************************************************************/
const Animate* Animateset::getAnimate(const String& name) const
{
	AnimateRegistry::const_iterator	pos = d_animates.find(name);

	if (pos == d_animates.end())
	{
		throw	UnknownObjectException("Animateset::getAnimate - The Animate named '" + name + "' could not be found in Animateset '" + d_name + "'.");
	}

	return pos->second;
}

/*************************************************************************
	add a new Animate.
*************************************************************************/
void Animateset::addAnimate(const String& name,bool bLoop,float fDelay)
{
	if (isAnimateDefined(name))
	{
		throw AlreadyExistsException("Animateset::addAnimate - An image with the name '" + name + "' already exists in Animateset '" + d_name + "'.");
	}

	d_animates[name] = new Animate(this,name,bLoop,fDelay);
}

void Animateset::addAnimate(Animate* pAnimate)
{
	if (isAnimateDefined(pAnimate->getName()))
	{
		throw AlreadyExistsException("Animateset::addAnimate - An image with the name '" + pAnimate->getName() + "' already exists in Animateset '" + d_name + "'.");
	}

	d_animates[pAnimate->getName()] = pAnimate;
}


/*************************************************************************
	Queues an area of the associated Texture the be drawn on the screen.
	Low-level routine not normally used!
*************************************************************************/
void Animateset::draw(const Rect& source_rect, const Rect& dest_rect, float z, const Rect& clip_rect,const ColourRect& colours, QuadSplitMode quad_split_mode, QuadMaskMode quad_mask_mode, void* quad_mask_data ) const
{
	// FIXME: animate
}

/*************************************************************************
	Unload all data, leaving Animateset in a clean (but unusable) state
*************************************************************************/
void Animateset::unload(void)
{
	undefineAllAnimates();
}

void Animateset::writeXMLToStream(XMLSerializer& xml_stream) const
{
    // output Animateset tag
    xml_stream.openTag("Animateset")
        .attribute("Name", d_name);
    
    // output animates
    AnimateIterator animate = getIterator();
    while (!animate.isAtEnd())
    {
        animate.getCurrentValue()->writeXMLToStream(xml_stream);
        ++animate;
    }

    // output closing tag
    xml_stream.closeTag();
}


/*************************************************************************
	Return an iterator object that can be used to iterate over the Animate
	objects in the Animateset.
*************************************************************************/
Animateset::AnimateIterator Animateset::getIterator(void) const
{
	return AnimateIterator(d_animates.begin(), d_animates.end());
}


void Animateset::undefineAnimate(const String& name)
{
	d_animates.erase(name);

	CEGUI_LOGINSANE("Animate '" + name + "' has been removed from Animateset '" + d_name + "'.")
}


void Animateset::undefineAllAnimates(void)
{
	d_animates.clear();

	CEGUI_LOGINSANE("All animates have been removed from Animateset '" + d_name + "'.")
}

} // End of  CEGUI namespace section
